﻿using System;
using System.ComponentModel;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using WindowsPhoneMvp.Events;
using WindowsPhoneMvp.Phone.State;
using WindowsPhoneEssentials.Diagnostics;

namespace WindowsPhoneMvp.Phone
{
    ///<summary>
    /// A base implementation a WindowsPhone MVP page
    ///</summary>
    public class MvpPhoneApplicationPage : PhoneApplicationPage, IView, ISupportsState, IEventRoutingView
    {
        /// <summary>
        /// Occurs at the discretion of the view. For <see cref="MvpUserControl"/>
        /// implementations (the most commonly used), this is fired during the
        /// Load event.
        /// </summary>
        public event EventHandler Load = delegate { };
        public event EventHandler<NavigatingCancelEventArgs> NavigatingFrom = delegate { };
        public event EventHandler<NavigationEventArgs> NavigatedFrom = delegate { };
        public event EventHandler<NavigationEventArgs> NavigatedTo = delegate { };
        EventToPresenter IEventRoutingView.EventToPresenter { get; set; }

        internal ITraceAppender TraceContext { get; set; }

        bool throwExceptionIfNoPresenterBound;
        readonly bool registeredWithPageViewHost;

        /// <summary>
        /// Gets or sets whether the runtime should throw an exception if a presenter is not bound to this control.
        /// </summary>
        /// <value><c>true</c> if an exception should be thrown (default); otherwise, <c>false</c>.</value>
        public bool ThrowExceptionIfNoPresenterBound
        {
            get
            {
                return throwExceptionIfNoPresenterBound;
            }
            set
            {
                if (registeredWithPageViewHost)
                {
                    throw new InvalidOperationException("ThrowExceptionIfNoPresenterBound can only be set prior to the control's Init event. The best place to set it is in the control's constructor.");
                }
                throwExceptionIfNoPresenterBound = value;
            }
        }

        ///<summary>
        /// Instantiates a new MvpPhoneApplicationPage
        ///</summary>
        public MvpPhoneApplicationPage()
        {
            if (!DesignerProperties.IsInDesignTool)
            {
                ThrowExceptionIfNoPresenterBound = true;
                registeredWithPageViewHost = true;
                PageViewHost.Register(this);
                Loaded += MvpPhoneApplicationPageLoaded;
            }
        }

        void MvpPhoneApplicationPageLoaded(object sender, System.Windows.RoutedEventArgs e)
        {
            Load(sender, e);
            Loaded -= MvpPhoneApplicationPageLoaded;
            Util.MemoryUsage.GetMemoryUsage(this, TraceContext, "View Loaded");
        }

        private NavigationMode mode = NavigationMode.New;
        protected sealed override void OnNavigatingFrom(NavigatingCancelEventArgs e)
        {
            base.OnNavigatingFrom(e);
            mode = e.NavigationMode;
            NavigatingFrom(this, e);
        }

        protected sealed override void OnNavigatedFrom(NavigationEventArgs e)
        {
            base.OnNavigatedFrom(e);

            if(Tag is WeakReference && ((WeakReference)Tag).Target is PageViewHost)
            {
                var reference = ((WeakReference)Tag).Target as PageViewHost;
                if(reference != null)
                {
                    reference.PresenterBinder.NavigatedFrom(this, e.Uri.ToString() == "app://external/");
                }
            }

            NavigatedFrom(this, e);
        }

        protected sealed override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);

            if(Tag != null && Tag is WeakReference && ((WeakReference)Tag).Target is PageViewHost)
            {
                var pageViewHost = ((WeakReference)Tag).Target as PageViewHost;
                if(pageViewHost != null)
                {
                    pageViewHost
                        .PresenterBinder
                        .NavigatedTo(this,
                                     pageViewHost.NavigationContext.CurrentNavigationParser.Parse(e.Uri.ToString()),
                                     pageViewHost.PendingActivation);
                }
            }

            NavigatedTo(this, e);
        }
    }
}
